home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / calls.com / CALLS.C next >
Encoding:
C/C++ Source or Header  |  1986-03-20  |  18.6 KB  |  718 lines

  1. /************************************************************************/
  2. /*    Calls Program to analyse program calls                */
  3. /*    Reference: The C Programming Tutor  p223 - A. DeSouza 5/3/85        */
  4. /************************************************************************/
  5. /*             include files                    */
  6. /************************************************************************/
  7. #include <c:stdio.h>
  8. #include <a:calls.h>
  9.  
  10.  
  11. /************************************************************************/
  12. /*               external functions                  */
  13. /************************************************************************/
  14. extern NamePtrType FindNameEntry();
  15. extern NamePtrType LookFor();
  16. extern char *malloc();
  17.  
  18. /************************************************************************/
  19. /*               global variables                 */
  20. /************************************************************************/
  21. NamePtrType ActiveList [MAXDEPTH] ;
  22. /* used by output to avoid infinite recursion.
  23. */
  24. int BracketCount = 0 ;
  25. /* keeps track of the nesting of brackets. a function found when
  26.  * BracketCount is 0 must be its DEFINING occurence, since function
  27.  * invocations must always appear within some block of code.
  28. */
  29. FILE *FilePtr ; /*input file pointer */
  30. char *HashTable[HTSIZE] ;
  31. int  LineCount = 0 ;
  32. int  MaxActiveIndex = 0 ;
  33. /* Indexes ActiveList from 0 to MAXDEPTH.
  34. */
  35. NamePtrType NameListHead ;
  36. FILE *OutFile ;
  37. int  TabsPerPage = (PAPERWIDTH-MAXSYMLENGTH)/TABSIZE ;
  38. /* default number of pages per page
  39. */
  40. BOOL Terse = TRUE ;
  41.  
  42. /***********************************************************************/
  43. /*               main                           */
  44. /***********************************************************************/
  45.  
  46. VOID main(argc,argv)
  47. int    argc ;
  48. char   *argv [] ;
  49. {  /* main */
  50.       int      ActListIndex ;
  51.       int      ArgIndex = 1 ;
  52.       char      Identifier[MAXSYMLENGTH] ;
  53.       NamePtrType CallerPtr ;
  54.       char      FileName[80] ;
  55.       int      FunctionUse ;
  56.       int      HTIndex ;
  57.       NamePtrType NamePtr ;
  58.  
  59.       NameListHead = GenericNULL(NameType) ;
  60.  
  61.       /* initialize the hash table.
  62.       */
  63.       for (HTIndex = 0 ; (HTIndex < HTSIZE ) ; HTIndex++)
  64.      HashTable[HTIndex] = GenericNULL(char) ;
  65.  
  66.       /* the following are keywords that look like function
  67.      calls in C
  68.       */
  69.       InsertWord("for") ;
  70.       InsertWord("if") ;
  71.       InsertWord("return") ;
  72.       InsertWord("sizeof") ;
  73.       InsertWord("switch") ;
  74.       InsertWord("while") ;
  75.  
  76.       /* Initialize the active list
  77.       */
  78.       for (ActListIndex = 0 ; (ActListIndex < MAXDEPTH) ; )
  79.       ActiveList[ActListIndex++] = GenericNULL(NameType) ;
  80.  
  81.        /* there must be at least one command-line option
  82.        */
  83.        if (argc < 2) {
  84.        printf("USAGE: %s\n",USAGE) ;
  85.        exit(0) ;
  86.        }
  87.  
  88.        /* determine the input file and open it
  89.        */
  90.        if (ArgIndex < argc ) {
  91.       /* extract the filename from the command line */
  92.  
  93.       strcpy(FileName,argv[ArgIndex++]) ;
  94.       if (!(FilePtr = fopen(FileName,"r")))
  95.           Error("Specified file cannot be opened",TRUE);
  96.        }
  97.        /* parse the input stream and build the appropriate tables.
  98.        */
  99.        CallerPtr = GenericNULL(NameType) ;
  100.        while ((FunctionUse =
  101.            FindNextFunction(Identifier,CallerPtr)) != EOF )
  102.         if (FunctionUse == DEFINING )
  103.         CallerPtr = FindNameEntry(Identifier) ;
  104.         else
  105.         NewOccurrence(Identifier,CallerPtr) ;
  106.        /* if there are any command line arguments, they are the names
  107.       of the functions from which to begin the call charts
  108.        */
  109.        if (ArgIndex < argc) {
  110.        do {
  111.            if (NamePtr = LookFor(argv[ArgIndex])) {
  112.           Output(NamePtr,0) ;
  113.           printf("\n\n") ;
  114.           }
  115.           else
  116.           Error(
  117.           "starting function from command line not found",FALSE) ;
  118.        }
  119.        while ((++ArgIndex) < argc) ;
  120.        }
  121.        else {
  122.         /* print beginning with 'main', if there is one */
  123.         if (NamePtr = LookFor("main")) {
  124.            Output(NamePtr,0) ;
  125.            printf("\n\n") ;
  126.            NamePtr->CallCount = 1 ;
  127.          /* don't print "main" again later. */
  128.        }
  129.  
  130.        /* now print all functions not called by anyone else */
  131.        for (NamePtr = NameListHead ; NamePtr ;
  132.              NamePtr = NamePtr->NextNamePtr )
  133.         if (NamePtr-> CallCount == 0) {
  134.         Output(NamePtr,0) ;
  135.         printf("\n\n") ;
  136.         }
  137.        /* Finally, print any mutually recursive functions. */
  138.        for (NamePtr = NameListHead ; NamePtr ;
  139.               NamePtr = NamePtr->NextNamePtr)
  140.         if (NamePtr->FirstLineNumber == 0) {
  141.         Output(NamePtr,0) ;
  142.         printf("\n\n") ;
  143.         }
  144.       }
  145.  }  /* main */
  146.  
  147.  
  148. VOID Output(NamePtr, CurTab)
  149. NamePtrType        NamePtr;
  150. int                CurTab;
  151. /* A recursive routine that prints one tab for each level of
  152.  * nesting, then the name of the function called, followed by the
  153.  * next function called at the same level.  In doing this, it
  154.  * invokes itself to Output the names of the functions called by
  155.  * the current function.  It maintains an active list of functions
  156.  * currently being Output by the different levels of recursion,
  157.  * and if it finds itself asked to Output one which is already
  158.  * active, it terminates, marking that call with an asterisk.
  159.  */
  160. {        /* Output */
  161.     InstPtrType InstPtr;
  162.     int            LoopCount;
  163.     int            NumOfTabs = CurTab;
  164.     BOOL        PageOverflow;
  165.     int            TabCount;
  166.  
  167.     LineCount++;
  168.     printf("\n%4d",LineCount);
  169.     if (!(MakeActive(NamePtr)))
  170.         printf("*");  /* Calls nested too deep  */
  171.     else {
  172.         for (TabCount = 0; (NumOfTabs > TabsPerPage); TabCount++)
  173.             NumOfTabs -= TabsPerPage;
  174.         for (LoopCount = 0; (LoopCount < TabCount); LoopCount++)
  175.             printf("<");
  176.         printf(" ");
  177.         for (LoopCount = 0; (LoopCount < NumOfTabs); LoopCount++)
  178.             printf("\t");
  179.  
  180.         if (IsActive(NamePtr))    /* recursive call */
  181.             printf("%s [recursive]", NamePtr->FunctionName);
  182.         else {
  183.             InstPtr = NamePtr->FirstCallee;
  184.             if (InstPtr != GenericNULL(InstanceType))  {
  185.                 printf("%s", NamePtr->FunctionName);
  186.                 if (!Terse || (NamePtr->FirstLineNumber == 0))    {
  187.                     CurTab++;
  188.                     if (NamePtr->FirstLineNumber == 0)
  189.                         NamePtr->FirstLineNumber = LineCount;
  190.                     if ((CurTab > TabsPerPage) &&
  191.                             (CurTab % TabsPerPage == 1) &&
  192.                             (InstPtr->NextCallee
  193.                                 != GenericNULL(InstanceType)))    {
  194.                         printf(
  195.                 "\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _");
  196.                         printf(" _ _ _ _ _ _ _ _ _ _");
  197.                         PageOverflow = TRUE;
  198.                     }
  199.                     else PageOverflow = FALSE;
  200.  
  201.                     for ( ; (InstPtr != GenericNULL(InstanceType));
  202.                             InstPtr = InstPtr->NextCallee)
  203.                         Output(InstPtr->NameDefinition, CurTab);
  204.  
  205.                     if (PageOverflow)  {
  206.                         printf(
  207.                 "\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _");
  208.                         printf(" _ _ _ _ _ _ _ _ _ _");
  209.                         PageOverflow = FALSE;
  210.                     }
  211.                 }
  212.                 else if (InstPtr != GenericNULL(InstanceType))
  213.                     printf("... [see line %d]", NamePtr->FirstLineNumber);
  214.             }
  215.             else printf("%s", NamePtr->FunctionName);
  216.             /*  library, external, or macro call  */
  217.         }
  218.         BackUp();
  219.         if (NamePtr->FirstLineNumber == 0)
  220.             NamePtr->FirstLineNumber = LineCount;
  221.         }
  222.     }  /* Output */
  223.  
  224.  
  225. BOOL MakeActive(CurNameEntry)
  226. NamePtrType        CurNameEntry;
  227. /* Puts a pointer to the argument NameEntry into the ActiveList.
  228.  * FALSE is returned if the function fails because the function
  229.  * nesting is too deep; otherwise TRUE is returned.
  230.  */
  231. {    /* MakeActive  */
  232.     if (MaxActiveIndex < MAXDEPTH)    {
  233.         ActiveList[MaxActiveIndex++] = CurNameEntry;
  234.         return (TRUE);
  235.     }
  236.     else return (FALSE);
  237. }    /* MakeActive  */
  238.  
  239.  
  240. BOOL IsActive(CurNameEntry)
  241. NamePtrType        CurNameEntry;
  242. /* Checks if its argument is already on the actove list.  */
  243. {        /*  IsActive  */
  244.     int ActListIndex;
  245.  
  246.     for (ActListIndex =0; (ActListIndex < MaxActiveIndex-1);
  247.             ActListIndex++)
  248.         if (CurNameEntry == ActiveList[ActListIndex])
  249.             return (TRUE);
  250.     return (FALSE);
  251. }        /* IsActive */
  252.  
  253.  
  254. VOID BackUp ()
  255. /* Pops an item from the active list.
  256. */
  257. {        /*  BackUp  */
  258.     assert(MaxActiveIndex > 0);
  259.     ActiveList[MaxActiveIndex--] = NULL;
  260. }        /*  BackUp  */
  261.  
  262.  
  263. int FindNextFunction(Identifier, CurFunction)
  264. char  *Identifier ;
  265. NamePtrType CurFunction ;
  266. /* Sets its argument to the name of the next function found
  267.  * in the input stream. It returns as its value DEFINING if this
  268.  * is the DEFINING occurrence of the function, DEFINED if it is
  269.  * simply an invocation of the function, and EOF if the input stream
  270.  * is exhausted.
  271.  */
  272. {      /*FindNextFunction */
  273.     int CurChar ;
  274.  
  275.     while (TRUE) {
  276.     CurChar = getc(FilePtr) ;
  277.     if (IsStartingLetter(CurChar)) {
  278.        ungetc(CurChar,FilePtr) ;
  279.        Scan(Identifier) ;
  280.     }
  281.     else {
  282.         switch(CurChar) {
  283.         case '\t':
  284.         case BLANK:
  285.         /* Skip over white space */
  286.         break ;
  287.         case EOL:
  288.         /* Skip over preprocessor lines */
  289.         if ((CurChar = getc(FilePtr)) == '#' )
  290.             while ((CurChar = getc(FilePtr)) != EOL)
  291.              if (CurChar == '\\')
  292.                 getc(FilePtr) ; /*Continuation */
  293.         ungetc(CurChar,FilePtr) ;
  294.         break ;
  295.  
  296.         case '\'':
  297.         /* This doesn't work if the literal contains a quoted
  298.            apostrophe (\'). */
  299.         Identifier[0] = EOS ;
  300.         /* Skip over character literals */
  301.         while ((CurChar = getc(FilePtr)) != '\'')
  302.              if (CurChar == '\\')
  303.             getc(FilePtr) ; /* Continuation */
  304.         break ;
  305.  
  306.         case '\"':
  307.         /* This doesn't work if literal contains a quoted
  308.            quotation mark (\") */
  309.         /* skip over string literals */
  310.          while ((CurChar = getc(FilePtr)) != '\"')
  311.              if (CurChar == '\\')
  312.             getc(FilePtr) ; /* Continuation */
  313.         break ;
  314.  
  315.         case '\\':
  316.         Identifier[0] = EOS ;
  317.         getc(FilePtr) ;
  318.         break ;
  319.  
  320.         case '{':
  321.         BracketCount++ ;
  322.         Identifier[0] = EOS ;
  323.         getc(FilePtr) ;
  324.         break ;
  325.  
  326.         case '}':
  327.         BracketCount-- ;
  328.         if (BracketCount < 0 )
  329.               Error("Brackets are not properly nested",FALSE) ;
  330.         Identifier[0] = EOS ;
  331.         break ;
  332.  
  333.         case '(':
  334.         if (Identifier[0] == EOS)
  335.             break ; /* No function name was found. */
  336.  
  337.         /* Ignore any works occurring in the hash table */
  338.         if ( !FindWord(Identifier)) {
  339.            /* Not within the body of a function */
  340.            if (BracketCount == 0)
  341.               return(DEFINING) ;
  342.  
  343.            else if (!Seen(Identifier,CurFunction))
  344.               return(DEFINED) ;
  345.            /* Ignore nultiple occurances within a function */
  346.         }
  347.         Identifier[0] = EOS ;
  348.         break ;
  349.  
  350.         case EOF:
  351.         return(EOF) ;
  352.  
  353.         case '/':
  354.         if ((CurChar = getc(FilePtr)) == '*') {
  355.            /* Skip over comments */
  356.            while (TRUE) {
  357.               while ( getc(FilePtr) != '*') ;
  358.               if ((CurChar = getc(FilePtr)) == '/')
  359.              break;
  360.               ungetc(CurChar,FilePtr) ;
  361.            }
  362.         }
  363.         else ungetc(CurChar,FilePtr) ;
  364.         break ;
  365.  
  366.          /* All over characters must delimit Identifiers */
  367.          default:
  368.          Identifier[0] = EOS ;
  369.          break ;
  370.  
  371.          }     /* switch */
  372.       } /* else */
  373.       } /* while */
  374.    } /* FindNextFunction */
  375.  
  376.  
  377. VOID Scan(Token)
  378. char *Token ;
  379. /* Scans the input stream until a token is found that might
  380.    be the name of a function. It returns the atom found. */
  381.     {    /* Scan */
  382.      int CurChar ;
  383.      int StringIndex ;
  384.  
  385.      for (StringIndex = 0 ;
  386.      CurChar = getc(FilePtr), IsStartingLetter(CurChar) ; ) {
  387.      Token[StringIndex++] = CurChar ;
  388.      if (StringIndex >= MAXSYMLENGTH) {
  389.           StringIndex = MAXSYMLENGTH - 1 ;
  390.           break ;
  391.      }
  392.      }
  393.      assert(StringIndex < MAXSYMLENGTH) ;
  394.      Token[StringIndex] = EOS ;
  395.      ungetc(CurChar,FilePtr) ;
  396.  } /* Scan  */
  397.  
  398.  
  399.  
  400. BOOL FindWord(Word)
  401. char *Word ;
  402. /* Looks up an identifier in the hash table and returns TRUE or
  403.    FALSE to indicate the presence or absence of the identifier */
  404. {     /* FindWord */
  405.      int Hash();
  406.      int HTIndex = Hash(Word) ;
  407.      if ((HTIndex == HASHTABLEFULLFLAG) ||
  408.       (HashTable[HTIndex] == GenericNULL(char)))
  409.       return(FALSE) ;
  410.      return(TRUE) ;
  411. } /* FindWord */
  412.  
  413.  
  414.  
  415.  
  416. BOOL Seen(CheckID, CurFunction)
  417. char *CheckID ;
  418. NamePtrType CurFunction ;
  419. /* Determines if the argument string CheckID has already been
  420.    seen as an argument function */
  421. { /* Seen  */
  422.      InstPtrType InstPtr ;
  423.  
  424.      assert(CurFunction != GenericNULL(NameType)) ;
  425.  
  426.      for (InstPtr = CurFunction ->FirstCallee ;
  427.       (InstPtr != GenericNULL(InstanceType)) ;
  428.       InstPtr = InstPtr->NextCallee)
  429.     if (StrEq(CheckID,(InstPtr->NameDefinition)->FunctionName))
  430.       return(TRUE) ;
  431.  
  432.      return (FALSE) ;
  433.  
  434. } /*Seen */
  435.  
  436.  
  437.  
  438. NamePtrType FindNameEntry(Name)
  439. char *Name ;
  440. /* Returns a pointer to the argument name on the list of
  441.    Nameentries. if the name is not there, a new Nameentry
  442.    is created */
  443.  
  444. {   /* FindNameEntry */
  445.      NamePtrType LastNamePtr = NULL ;
  446.      NamePtrType NamePtr ;
  447.      NamePtrType NewNamePtr ;
  448.      NamePtrType AllocNameEntry() ;
  449.      int StrTest ;
  450.  
  451.      /* Search for the name in the current list of known, defined
  452.     functions. since the names are inserted in sorted order,
  453.     stop when we have passed the new name in the list. */
  454.  
  455.      for(NamePtr = NameListHead ;
  456.            NamePtr != NULL &&
  457.          (StrTest = strcmp(Name,NamePtr->FunctionName)) >= 0 ;
  458.            LastNamePtr = NamePtr,
  459.          NamePtr = NamePtr->NextNamePtr)
  460.      if ( StrTest == 0 )
  461.            return(NamePtr) ;
  462.  
  463.      /* Name was not found, so add it */
  464.  
  465.      NewNamePtr = AllocNameEntry();
  466.      strcpy(NewNamePtr->FunctionName,Name) ;
  467.  
  468.      /* Link the new name entry into the appropriate place in the chain */
  469.      NewNamePtr->NextNamePtr = NamePtr ;
  470.      if (!LastNamePtr)
  471.       NameListHead = NewNamePtr ;
  472.      else
  473.       LastNamePtr->NextNamePtr = NewNamePtr ;
  474.      return (NewNamePtr) ;
  475.  
  476. } /* FindNameEntry */
  477.  
  478.  
  479.  
  480.  
  481. NamePtrType AllocNameEntry()
  482. /* Allocates storage for a NameEntry */
  483. {   /* AllocNameEntry */
  484.      NamePtrType NamePtr ;
  485.  
  486.      if (!(NamePtr = GenericMalloc(NameType)))
  487.       Error("Ran out of memory",TRUE) ;
  488.  
  489.      /* Initialize the new entry */
  490.      NamePtr->FunctionName[0]     = EOS ;
  491.      NamePtr->CallCount    = 0 ;
  492.      NamePtr->FirstLineNumber     = 0 ;
  493.      NamePtr->FirstCallee    = GenericNULL(InstanceType) ;
  494.      NamePtr->NextNamePtr    = GenericNULL(NameType) ;
  495.  
  496.      return (NamePtr) ;
  497.  
  498. } /* AllocNameEntry */
  499.  
  500.  
  501.  
  502.  
  503. VOID NewOccurrence(Name,CallerPtr)
  504. char *Name ;
  505. NamePtrType CallerPtr;
  506. /* Creates an instanceentry for a function use */
  507. {   /* NewOccurrence */
  508.      InstPtrType InstPtr ;
  509.      NamePtrType NamePtr ;
  510.      InstPtrType NewInstPtr ;
  511.      InstPtrType AllocInstanceEntry();
  512.  
  513.      assert(CallerPtr != GenericNULL(NameType)) ;
  514.  
  515.      /* Create the new instance and link it with a NameType describing it */
  516.      InstPtr = CallerPtr->FirstCallee ;
  517.      NamePtr = FindNameEntry(Name) ;
  518.      NewInstPtr = AllocInstanceEntry() ;
  519.      NewInstPtr->NameDefinition = NamePtr ;
  520.  
  521.      if (InstPtr != GenericNULL(InstanceType)) {
  522.       /* Run down the callee chain until a NULL link is found */
  523.       for ( ; (InstPtr->NextCallee != GenericNULL(InstanceType)) ;
  524.             InstPtr = InstPtr->NextCallee)
  525.         ; /* no body */
  526.  
  527.        /* Now add the new instance to the callee chain */
  528.        InstPtr->NextCallee = NewInstPtr ;
  529.  
  530.      }
  531.      else
  532.       CallerPtr->FirstCallee = NewInstPtr ;
  533.  
  534.       /* Increment the callee's call count */
  535.  
  536.      (NamePtr->CallCount)++ ;
  537.  
  538. } /* NewOccurrance */
  539.  
  540.  
  541.  
  542.  
  543.  
  544. InstPtrType AllocInstanceEntry()
  545. /* Allocates storage for InstanceEntry */
  546. {   /* AllocInstanceEntry */
  547.      InstPtrType InstPtr ;
  548.      if (!(InstPtr = GenericMalloc(InstanceType)))
  549.       Error("Ran out of memory",TRUE) ;
  550.  
  551.      InstPtr->NameDefinition = GenericNULL(NameType) ;
  552.      InstPtr->NextCallee     = GenericNULL(InstanceType) ;
  553.  
  554.      return(InstPtr) ;
  555.  
  556. }  /* AllocInstanceEntry */
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566. NamePtrType LookFor(Name)
  567. char *Name ;
  568. /* Looks for its argument name on the list of NameEntries
  569.    if found, it returns a pointer to the entry; otherwise
  570.    , it returns a NULL. */
  571.  
  572. {    /* LookFor */
  573.      NamePtrType NamePtr ;
  574.  
  575.      for (NamePtr = NameListHead ;
  576.            (NamePtr != GenericNULL(NameType)) ;
  577.            NamePtr = NamePtr->NextNamePtr)
  578.  
  579.      if (StrEq(Name,NamePtr->FunctionName))
  580.           return(NamePtr) ;
  581.  
  582.      return(GenericNULL(NameType)) ;
  583.  
  584. } /* LookFor */
  585.  
  586.  
  587. char *Copy(OldString)
  588. char *OldString ;
  589. /* Copy makes a copy of OldString and returns the address of the copy */
  590. {  /* Copy */
  591.     char *NewString ;
  592.     char *ReturnPtr ;
  593.  
  594.     /* allocate a string able to hold the length
  595.        of the string plus one for the terminator */
  596.     ReturnPtr = NewString = malloc(strlen(OldString) + 1) ;
  597.  
  598.     /* Copy the string and return a pointer to it */
  599.     while (*NewString++ = *OldString++) ;
  600.     return(ReturnPtr) ;
  601.  
  602. }  /* Copy */
  603.  
  604.  
  605.  
  606.  
  607. VOID Error(Message,AbortFlag)
  608. /* Reports any errors detected */
  609. char *Message ;
  610. BOOL AbortFlag ;
  611. {  /* Error */
  612.     fprintf(stderr,"\n*** calls: %s. ***\n",Message) ;
  613.     if (AbortFlag)
  614.     exit(0) ;
  615.  
  616. } /* Error */
  617.  
  618.  
  619.  
  620. int Hash(Word)
  621. char *Word ;
  622. /* Generates a unique hash table index for the argument
  623.    identifier. the value of HASHTABLEFULLFLAG is returned
  624.    if the hash table overflows */
  625.  
  626. { /* Hash */
  627.     int HTIndex ;
  628.     int InitHTIndex ;
  629.     int ProbeCounter = 0 ;
  630.  
  631.     HTIndex = InitHTIndex = TransformId(Word) ;
  632.     assert(strlen(Word) > 0) ;
  633.  
  634.     if (HashTable[HTIndex] == GenericNULL(char))
  635.        ; /* no-op - we've got it */
  636.  
  637.     else /* Have we found the correct index */
  638.        if (StrEq(Word,HashTable[HTIndex]))
  639.       ; /* DONE: a direct hit */
  640.  
  641.        else /* Collision -- generate indexes */
  642.       for ( ; (ProbeCounter < (HTSIZE/2)) ; ProbeCounter++) {
  643.           HTIndex = GenerateNewIndex(InitHTIndex, ProbeCounter) ;
  644.           if ((HashTable[HTIndex] == GenericNULL(char))  ||
  645.            StrEq(Word,HashTable[HTIndex]))
  646.         break ; /* we've got it */
  647.       }
  648.      if (ProbeCounter >= (HTSIZE/2))
  649.      return(HASHTABLEFULLFLAG) ;
  650.      return(HTIndex) ;
  651.  
  652. } /* Hash */
  653.  
  654.  
  655.  
  656.  
  657. BOOL InsertWord(Word)
  658. char *Word ;
  659. /* Inserts an identifier into the Hash table and returns TRUE.
  660.    if the Hash table overflows, FALSE is returned */
  661.  
  662. { /* InsertWord */
  663.    int HTIndex ;
  664.  
  665.    if ((HTIndex = Hash(Word)) == HASHTABLEFULLFLAG)
  666.       return(FALSE) ;
  667.  
  668.    /* add Word to the Hash table if it is not already present */
  669.    if (HashTable[HTIndex] == GenericNULL(char))
  670.        HashTable[HTIndex] = Copy(Word) ;
  671.  
  672.    return(TRUE) ;
  673.  
  674. } /* InsertWord */
  675.  
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
  682. BOOL IsStartingLetter(Ch)
  683. char Ch ;
  684. /* IsStartingLetter returns TRUE if Ch is a valid character to
  685.    begin a C token */
  686.  
  687. { /* IsStartingLetter */
  688.     return((isalpha(Ch) || Ch == '_') ? TRUE : FALSE) ;
  689.  
  690. } /* IsStartingLetter */
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697. int TransformId(Word)
  698. char Word[] ;
  699. /* Converts an identifier into an integer within the index
  700.    range of HashTable. a ploynomial is generated and reduced
  701.    modulo HTSIZE to produce this number */
  702.  
  703. { /* TransformId */
  704.     int Term = 0 ;
  705.     int Wordindex ;
  706.  
  707.     for (Wordindex = strlen(Word)-1 ; (Wordindex >= 0) ; Wordindex--)
  708.        Term = (257*Term) + Word[Wordindex] ;
  709.  
  710.     Term = abs(Term) ;
  711.     return(Term % HTSIZE ) ;
  712.  
  713. } /* TransformId */
  714.  
  715.  
  716.  
  717.  
  718.